package org.jclosures.collections.impl;

import java.util.Collection;
import java.util.Iterator;

import org.jclosures.collections.FunctionalCollection;
import org.jclosures.function.Function1;
import org.jclosures.function.Function2;

public class FunctionalCollectionDelegateDecorator<E> implements
		FunctionalCollection<E> {

	private Collection<E> decoratedCollection;

	public FunctionalCollectionDelegateDecorator(Collection<E> decoratedCollection) {
		super();
		this.decoratedCollection = decoratedCollection;
	}

	@Override
	public boolean add(E e) {
		return this.decoratedCollection.add(e);
	}

	@Override
	public boolean addAll(Collection<? extends E> c) {
		return this.decoratedCollection.addAll(c);
	}

	@Override
	public void clear() {
		this.decoratedCollection.clear();
	}

	@Override
	public boolean contains(Object o) {
		return this.decoratedCollection.contains(o);
	}

	@Override
	public boolean containsAll(Collection<?> c) {
		return this.decoratedCollection.containsAll(c);
	}

	@Override
	public boolean isEmpty() {
		return this.decoratedCollection.isEmpty();
	}

	@Override
	public Iterator<E> iterator() {
		return this.decoratedCollection.iterator();
	}

	@Override
	public boolean remove(Object o) {
		return this.decoratedCollection.remove(o);
	}

	@Override
	public boolean removeAll(Collection<?> c) {
		return this.decoratedCollection.removeAll(c);
	}

	@Override
	public boolean retainAll(Collection<?> c) {
		return this.decoratedCollection.retainAll(c);
	}

	@Override
	public int size() {
		return this.decoratedCollection.size();
	}

	@Override
	public Object[] toArray() {
		return this.decoratedCollection.toArray();
	}

	@Override
	public <T> T[] toArray(T[] a) {
		return this.decoratedCollection.toArray(a);
	}

	@SuppressWarnings("unchecked")
	@Override
	public <F> FunctionalCollection<F> map(Function1<E, F> f) {

		try {
			FunctionalCollection<F> result = new FunctionalCollectionDelegateDecorator<F>(
					this.decoratedCollection.getClass().newInstance());

			for (E value : this.decoratedCollection) {
				result.add(f.apply(value));
			}
			return result;
		} catch (InstantiationException e) {
		} catch (IllegalAccessException e) {
		}
		return null;
	}

	public <RT> RT fold(Function2<E, RT, RT> f, RT e) {
		RT base = e;
		for (E value : this) {
			base = f.apply(value, base);
		}
		return base;
	};

}
